//package java_cup.runtime;

//import java.util.Arrays;
//import java.util.LinkedList;
//import java.util.List;
//import java.util.Stack;

public class SyntaxTreeTransform {
    public static XMLElement[] X = new XMLElement[0];

    public class ListFlattener : SyntaxTreeDFS.AbstractVisitor {
        public List<String> name;

        public ListFlattener(params String[] name) {
            this.name = new List<string>(name);
        }

        public XMLElement root() {
            System.Console.WriteLine(stack.Count + " - " + intstack.Count);
            return stack.Pop();
        }

        public Stack<XMLElement> stack = new();
        public Stack<int> intstack = new();

        /*@Override*/
        public override void defaultPre(XMLElement element, List<XMLElement> children) {
            intstack.Push(children.Count);
        }

        /*@Override*/
        public override void defaultPost(XMLElement element, List<XMLElement> children) {
            int n = intstack.Pop();
            if (n > 0) {
            outer: do {
                    if (name.Contains(element.Tagname))
                        foreach (XMLElement e in children)
                            if (e.Tagname.Equals(element.Tagname)) {
                                goto outer;
                            }
                    LinkedList<XMLElement> elems = new();
                    while (n-- > 0)
                        elems.AddFirst(stack.Pop());
                    stack.Push(new XMLElement.NonTerminalXml(element.Tagname,
                        0, elems.ToArray()));
                    System.Console.WriteLine("  doch noch: ");
                    return;
                } while (false);
                {
                    LinkedList<XMLElement> elems = new();
                    while (n-- > 0) {
                        elems.AddFirst(stack.Pop());
                    }
                    //stack.addAll(elems);
                    foreach (var item in elems) {
                        stack.Push(item);
                    }
                }
                intstack.Push(intstack.Pop() + n - 1);
            }
            if (n == 0) {
                stack.Push(element);
            }
        }

    }

    public XMLElement flattenLists(XMLElement elem, params String[] names) {
        ListFlattener cr = new ListFlattener(names);
        SyntaxTreeDFS.dfs(elem, cr);
        return cr.root();
    }

    public class ChainRemover : SyntaxTreeDFS.AbstractVisitor {
        public XMLElement root() {
            return stack.Pop();
        }

        public Stack<XMLElement> stack = new Stack<XMLElement>();

        /*@Override*/
        public override void defaultPost(XMLElement arg0, List<XMLElement> arg1) {
            int n = arg1.Count;
            if (n > 1) {
                LinkedList<XMLElement> elems = new();
                while (n-- > 0)
                    elems.AddFirst(stack.Pop());
                XMLElement.NonTerminalXml non = (XMLElement.NonTerminalXml)arg0;
                XMLElement ne = new XMLElement.NonTerminalXml(arg0.Tagname,
                    non.getVariant(), elems.ToArray());
                stack.Push(ne);
                return;
            }
            // if (n==1){}
            if (n == 0)
                stack.Push(arg0);
        }

        /*@Override*/
        public override void defaultPre(XMLElement arg0, List<XMLElement> arg1) {
        }

    }

    public XMLElement removeUnaryChains(XMLElement elem) {
        ChainRemover cr = new ChainRemover();
        SyntaxTreeDFS.dfs(elem, cr);
        return cr.root();
    }

}
